package com.fxu.tpl.api;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.IoUtil;
import cn.hutool.poi.excel.ExcelUtil;
import cn.hutool.poi.excel.ExcelWriter;
import com.fxu.framework.core.base.Result;
import com.fxu.framework.core.dto.DetailReq;
import com.fxu.framework.core.exception.MsgException;
import com.fxu.framework.core.service.impl.ApiServiceImpl;
import com.fxu.framework.core.sql.SUtils;
import com.fxu.framework.core.util.MapUtil;
import com.fxu.gen.AutoUtil;
import com.fxu.gen.Entity;
import com.fxu.gen.Mapper;
import com.fxu.gen.VueHtml;
import com.fxu.gen.enums.TplEnum;
import com.fxu.tpl.entity.*;
import com.fxu.tpl.rest.TableRestImpl;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.*;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;
import java.io.IOException;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/***
 * <p>小飞鼠</p>
 * [table]的Restfull接口
 * @author fangxu
 * @version 2019-07-16
 ***/
@RestController
@RequestMapping("/api/table")
@Api(tags = "表的管理")
@RequiredArgsConstructor
public class TableController {
	private final TableRestImpl tableRestImpl;
	private final ApiServiceImpl apiRestImpl;

	@PostMapping("/autoGen/")
	@ApiOperation("自动生成vue代码")
	public Result<String> autoGen(@RequestBody @Valid List<String> ids) {
		return tableRestImpl.autoGen(ids);
	}
	
	@PostMapping("/modifySql/")
	@ApiOperation("修改表结构的SQL语句")
	public Result<String> modifySql(@RequestBody @Valid List<String> ids) {
		return tableRestImpl.modifySql(ids);
	}

	@PostMapping("/createSql/")
	@ApiOperation("创建表结构的SQL语句")
	public Result<String> createSql(@RequestBody @Valid List<String> ids) {
		return tableRestImpl.createSql(ids);
	}

	@PostMapping("/vbenSchemas/")
	@ApiOperation("vben的Schema")
	public Result<String> vbenSchemas(@RequestBody @Valid List<String> ids) {
		return tableRestImpl.vbenSchemas(ids);
	}

	@PostMapping("/tableBySql/")
	@ApiOperation("创建表结构的SQL语句")
	public Result<Table> tableBySql(@RequestBody @Valid Map<String, Object> map) {
		return Result.ok(tableRestImpl.getTableBySQL(MapUtil.getStrNotEmpty(map, "sql")));
	}

	@PostMapping("/changeId/")
	@ApiOperation("互换两个表ID")
	public Result<String> changeId(@RequestBody @Valid List<Long> ids) {
		if (CollUtil.isEmpty(ids) || ids.size() != 2) {
			return Result.error("入参数有误!");
		}
		Long id1 = ids.get(0);
		Long id2 = ids.get(1);
		apiRestImpl.updateBy(SUtils.update(Table.class).id(id1).set(Table::getId, -1));
		apiRestImpl.updateBy(SUtils.update(Column.class).eq(Column::getTableId, id1).set(Column::getTableId, -1));
		apiRestImpl.updateBy(SUtils.update(Column.class).eq(Column::getLinkTableId, id1).set(Column::getLinkTableId, -1));
		apiRestImpl.updateBy(SUtils.update(Index.class).eq(Index::getTableId, id1).set(Index::getTableId, -1));
		apiRestImpl.updateBy(SUtils.update(Link.class).eq(Link::getTableId, id1).set(Link::getTableId, -1));
		apiRestImpl.updateBy(SUtils.update(Link.class).eq(Link::getLinkTableId, id1).set(Link::getLinkTableId, -1));
		apiRestImpl.updateBy(SUtils.update(TableLog.class).eq(TableLog::getTableId, id1).set(TableLog::getTableId, -1));

		apiRestImpl.updateBy(SUtils.update(Table.class).id(id2).set(Table::getId, id1));
		apiRestImpl.updateBy(SUtils.update(Column.class).eq(Column::getTableId, id2).set(Column::getTableId, id1));
		apiRestImpl.updateBy(SUtils.update(Column.class).eq(Column::getLinkTableId, id2).set(Column::getLinkTableId, id1));
		apiRestImpl.updateBy(SUtils.update(Index.class).eq(Index::getTableId, id2).set(Index::getTableId, id1));
		apiRestImpl.updateBy(SUtils.update(Link.class).eq(Link::getTableId, id2).set(Link::getTableId, id1));
		apiRestImpl.updateBy(SUtils.update(Link.class).eq(Link::getLinkTableId, id2).set(Link::getLinkTableId, id1));
		apiRestImpl.updateBy(SUtils.update(TableLog.class).eq(TableLog::getTableId, id2).set(TableLog::getTableId, id1));

		apiRestImpl.updateBy(SUtils.update(Table.class).id(-1).set(Table::getId, id2));
		apiRestImpl.updateBy(SUtils.update(Column.class).eq(Column::getTableId, -1).set(Column::getTableId, id2));
		apiRestImpl.updateBy(SUtils.update(Column.class).eq(Column::getLinkTableId, -1).set(Column::getLinkTableId, id2));
		apiRestImpl.updateBy(SUtils.update(Index.class).eq(Index::getTableId, -1).set(Index::getTableId, id2));
		apiRestImpl.updateBy(SUtils.update(Link.class).eq(Link::getTableId, -1).set(Link::getTableId, id2));
		apiRestImpl.updateBy(SUtils.update(Link.class).eq(Link::getLinkTableId, -1).set(Link::getLinkTableId, id2));
		apiRestImpl.updateBy(SUtils.update(TableLog.class).eq(TableLog::getTableId, -1).set(TableLog::getTableId, id2));
		return Result.ok("成功");
	}

	@ApiOperation("预览代码")
	@PostMapping("/preview/")
	public Result<Object> preview(@RequestBody @Valid DetailReq req) {
		Table table = tableRestImpl.getTable(req.getId() + "");
		if (table == null) {
			throw new MsgException("入参有误!id=" + req.getId());
		}
		List<Map<String, Object>> genList = new ArrayList<>();
		genList.add(MapUtil.put("name", "Entity").put("content", new Entity(table, tableRestImpl.getNewFile(table, TplEnum.Entity)).doReplace()).build());
		genList.add(MapUtil.put("name", "Mapper").put("content", new Mapper(table, tableRestImpl.getNewFile(table, TplEnum.Mapper)).doReplace()).build());
		genList.add(MapUtil.put("name", "Vue").put("content", new VueHtml(table, tableRestImpl.getNewFile(table, TplEnum.VueHtml)).doReplace()).build());
		return Result.ok(genList);
	}
	
	@PostMapping("/tableToExcel/")
	@ApiOperation("表结构导出excel")
	public void tableToExcel(@RequestBody List<Serializable> tableIds, HttpServletResponse response) throws IOException {
		List<Table> tables = apiRestImpl.listBy(SUtils.query(Table.class).ids(tableIds));
		ExcelWriter writer = ExcelUtil.getWriter();
		writer.merge(7, "表结构");
		for (Table table : tables) {
			ArrayList<List<Object>> rows = new ArrayList<>();
			//table.setLinkList(apiRestImpl.listBy(new SQuery<Link>(Link.class){}.eq(Link::getTableId, table.getId())));
			rows.add(CollUtil.toList("字段名", "字段类型", "not null", "字段说明", "限定说明", "对应属性", "关联", "日期"));
			for (Column column : apiRestImpl.listBy(SUtils.query(Column.class)
					.eq(Column::getTableId, table.getId()).orderAsc(Column::getOrderNo).orderAsc(Column::getId))) {
				if (column.getLinkTableId() != null && column.getLinkTableId() > 0) {
					column.setLinkTable(apiRestImpl.findLast(SUtils.query(Table.class).id(column.getLinkTableId()).show(Table::getName)));
				}
				rows.add(CollUtil.toList(column.getName(),
						AutoUtil.getSqlType(column) + (column.getLength() <= 0 ? "" : "("+column.getLength()+")"),
						column.getNotNull() ? "是" : "", column.getCmmt(), column.getLimits(),
						AutoUtil.firstLowerBean(column.getName()),
						column.getLinkTable() == null ? "" : column.getLinkTable().getName() + ".id",
						column.getCreateTime() == null ? "" : DateUtil.formatDate(column.getCreateTime())));
			}

			rows.add(CollUtil.toList("索引名", "索引字段", "说明", "日期"));
			for (Index index : apiRestImpl.listBy(SUtils.query(Index.class).eq(Index::getTableId, table.getId()).orderAsc(Index::getId))) {
				rows.add(CollUtil.toList(index.getName(),
						index.getColumns(), "",
						index.getCreateTime() == null ? "" : DateUtil.formatDate(index.getCreateTime())));
			}
			writer.write(CollUtil.toList(""));
			writer.merge(7, table.getName() + "("+table.getCmmt()+")");
			writer.write(rows, true);
		}

		response.setContentType("application/vnd.ms-excel;charset=utf-8");
		response.setHeader("Content-Disposition","attachment;filename=tables.xls");
		ServletOutputStream out = response.getOutputStream();

		writer.flush(out, true);
		writer.close();
		IoUtil.close(out);
	}
}